package cn.wen.yaling.xo.service.impl;

import cn.wen.yaling.commons.constant.RedisConstants;
import cn.wen.yaling.commons.entity.ImageEntity;
import cn.wen.yaling.commons.entity.TypeEntity;
import cn.wen.yaling.commons.enums.*;
import cn.wen.yaling.commons.service.RedisService;
import cn.wen.yaling.commons.utils.*;
import cn.wen.yaling.commons.vo.QuestionAddVO;
import cn.wen.yaling.commons.vo.QuestionAdminListVO;
import cn.wen.yaling.commons.vo.QuestionListVO;
import cn.wen.yaling.commons.vo.QuestionUpdateVO;
import cn.wen.yaling.xo.dao.ImageDao;
import cn.wen.yaling.xo.dao.TypeDao;
import cn.wen.yaling.xo.service.CommentService;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.wen.yaling.xo.dao.QuestionsDao;
import cn.wen.yaling.commons.entity.QuestionsEntity;
import cn.wen.yaling.xo.service.QuestionsService;
import org.springframework.transaction.annotation.Transactional;


@Service("questionsService")
public class QuestionsServiceImpl extends ServiceImpl<QuestionsDao, QuestionsEntity> implements QuestionsService {

    @Autowired
    private QuestionsDao questionsDao;

    @Autowired
    private CommentService commentService;

    @Autowired
    private ImageDao imageDao;

    @Autowired
    private RedisService redisService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private TypeDao typeDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<QuestionsEntity> page = this.page(
                new Query<QuestionsEntity>().getPage(params),
                new QueryWrapper<QuestionsEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<QuestionListVO> getAllIsActiveQuestionList() {
        // 问答的内容变化不会很大  但是评论数据变化的概率会更大  使用只能保存问答的内容
        List<QuestionListVO> questionListVOS;
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(RedisConstants.CACHE_WEB_QUESTION_ALL_LIST)) {
            questionListVOS = redisUtils.getListCache(RedisConstants.CACHE_WEB_QUESTION_ALL_LIST, QuestionListVO.class);
        } else {
            // 2、获取全部激活的问题列表  包括类别
            questionListVOS = questionsDao.getAllIsActiveQuestionList();
            // 3、需要对其中的评论数量进行添加
            for (QuestionListVO questionListVO : questionListVOS) {
                questionListVO.setQuestionAnswerNum(commentService.getCommentNumByQuestionId(questionListVO.getQuestionId()));
            }
            // 4、将db中的缓存获取到
            redisUtils.setListCache(RedisConstants.CACHE_WEB_QUESTION_ALL_LIST, questionListVOS);
        }

        return questionListVOS;
    }

    @Transactional
    @Override
    public ResultEntity publishQuestion(QuestionAddVO questionAddVO, Integer typeId) {
        QuestionsEntity questionsEntity = new QuestionsEntity();
        BeanUtils.copyProperties(questionAddVO, questionsEntity);
        // 审核状态
        questionsEntity.setQuestionStatus(QuestionStatus.UNDER_REVIEW.getStatus());
        int result = addQuestionDB(typeId, questionsEntity);
        if (result < 1) return ResultEntity.error(HttpCode.内部服务器错误.getCode(), "发表文章失败！");
        // 删除问答数据缓存
        redisUtils.delQuestionListCache();
        return ResultEntity.ok();
    }

    @Override
    public List<QuestionsEntity> getHotQuestionList() {
        QueryWrapper<QuestionsEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("question_status", QuestionStatus.ALREADY_PASSED.getStatus());
        queryWrapper.eq("is_publish", 1);
        queryWrapper.orderByDesc("question_views");
        queryWrapper.last("limit 0, " + LimitNum.TEN.getNum());
        return questionsDao.selectList(queryWrapper);
    }

    @Override
    public QuestionsEntity getQuestionInfoByQuestionId(Integer questionId) {
        return questionsDao.selectById(questionId);
    }

    @Override
    public ResultEntity getAllNotDeleteQuestionList() {
        List<QuestionAdminListVO> questionList;
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(RedisConstants.CACHE_ADMIN_QUESTION_ALL_LIST)) {
            questionList = redisUtils.getListCache(RedisConstants.CACHE_ADMIN_QUESTION_ALL_LIST, QuestionAdminListVO.class);
        } else {
            // 2.未命中缓存
            QueryWrapper<QuestionsEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.ne("question_status", QuestionStatus.NO_PASS);
            List<QuestionsEntity> questions = questionsDao.selectList(queryWrapper);
            if (questions.size() == 0) return ResultEntity.error();
            questionList = questions.stream().map((item) -> {
                QuestionAdminListVO target = new QuestionAdminListVO();
                BeanUtils.copyProperties(item, target);
                target.setTypeId(questionsDao.getQuestionTypeId(target.getQuestionId()));
                return target;
            }).collect(Collectors.toList());
            // 4、将db中的缓存获取到
            redisUtils.setListCache(RedisConstants.CACHE_ADMIN_QUESTION_ALL_LIST, questionList);
        }
        return ResultEntity.ok().put("data", questionList);
    }

    @Transactional
    @Override
    public ResultEntity addQuestion(QuestionAddVO questionAddVO) {
        QuestionsEntity questionsEntity = new QuestionsEntity();
        BeanUtils.copyProperties(questionAddVO, questionsEntity);
        // 审核状态
        questionsEntity.setQuestionStatus(QuestionStatus.ALREADY_PASSED.getStatus());
        int result = addQuestionDB(questionAddVO.getTypeId(), questionsEntity);
        if (result < 1) return ResultEntity.error(HttpCode.内部服务器错误.getCode(), "发表问答失败！");
        redisUtils.delQuestionListCache();
        return ResultEntity.ok();
    }

    @Override
    public ResultEntity updateQuestion(QuestionUpdateVO question) {
        QuestionsEntity target = new QuestionsEntity();
        BeanUtils.copyProperties(question, target);
        target.setUpdateTime(new Date());
        if (!question.isComment) {
            target.setQuestionStatus(QuestionStatus.NO_PASS.getStatus());
        } else {
            target.setQuestionStatus(QuestionStatus.ALREADY_PASSED.getStatus());
        }
        int res = questionsDao.updateById(target);
        if (res > 0) {
            redisUtils.delQuestionListCache();
            return ResultEntity.ok();
        }
        return ResultEntity.error();
    }

    @Override
    public ResultEntity updateQuestionStatus(Integer questionId, Integer status) {
        QuestionsEntity target = new QuestionsEntity();
        target.setQuestionId(questionId);
        target.setQuestionStatus(status);
        boolean res = questionsDao.updateById(target) > 0;
        if (res) {
            redisUtils.delQuestionListCache();
            return ResultEntity.ok();
        }
        return ResultEntity.error();
    }

    @Override
    public ResultEntity updateQuestionIsComment(Integer questionId, boolean isComment) {
        QuestionsEntity target = new QuestionsEntity();
        target.setQuestionId(questionId);
        target.setIsComment(isComment);
        boolean res = questionsDao.updateById(target) > 0;
        if (res) {
            redisUtils.delQuestionListCache();
            return ResultEntity.ok();
        }
        return ResultEntity.error();
    }

    @Override
    public ResultEntity searchAllNotDeleteQuestionList(String keyword) {
        QueryWrapper<QuestionsEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.ne("question_status", QuestionStatus.NO_PASS);
        queryWrapper.like("question_title", keyword);
        List<QuestionsEntity> questions = questionsDao.selectList(queryWrapper);
        if (questions.size() == 0) return ResultEntity.error();
        List<QuestionAdminListVO> list = questions.stream().map((item) -> {
            QuestionAdminListVO target = new QuestionAdminListVO();
            BeanUtils.copyProperties(item, target);
            return target;
        }).collect(Collectors.toList());
        return ResultEntity.ok().put("data", list);
    }

    @Transactional
    @Override
    public ResultEntity deleteBatchQuestion(Integer[] questionIds) {
        boolean res = questionsDao.updateBatchQuestion(questionIds, QuestionStatus.NO_PASS.getStatus());
        if (res) {
            redisUtils.delQuestionListCache();
            return ResultEntity.ok();
        }
        return ResultEntity.error();
    }

    @Override
    public ResultEntity getQuestionTypeList() {
        List<TypeEntity> typeList;
        String cacheKey = RedisConstants.CACHE_ADMIN_QUESTION_TYPE_LIST + ":" + TypeSort.QUESTION.getStatus();
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(cacheKey)) {
            typeList = redisUtils.getListCache(cacheKey, TypeEntity.class);
        } else {
            // 2.未命中缓存
            QueryWrapper<TypeEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("type_status", TypeStatus.NORMAL_USE.getStatus());
            queryWrapper.eq("type_sort", TypeSort.QUESTION.getStatus());
            typeList = typeDao.selectList(queryWrapper);
            // 4、将db中的缓存获取到
            redisUtils.setListCache(cacheKey, typeList);
        }
        return ResultEntity.ok().put("data", typeList);
    }

    private int addQuestionDB(Integer typeId, QuestionsEntity questionsEntity) {
        // 1、需要先判断邮箱是否可用  如果是有效的邮箱则可以发送请求
        // 邮箱验证在工具层判断
        // 2、将密码进行MD5加密
        questionsEntity.setQuestionPassword(MD5Utils.createMD5(
                questionsEntity.getQuestionPassword() == null ?
                        "123456" : questionsEntity.getQuestionPassword()));
        // 3、设置基本信息
        questionsEntity.setCreateTime(new Date());
        questionsEntity.setUpdateTime(new Date());

        // 4、判断前端是否存在照片  就是头像  如果不存在则默认使用评论中的
        if (questionsEntity.getQuestionPhotoUrl() == null || "".equals(questionsEntity.getQuestionPhotoUrl())) {
            List<ImageEntity> images = imageDao.getCommentAvatarList();
            questionsEntity.setQuestionPhotoUrl(images.get(RandomUtils.nextInt(0, images.size())).getImageUrl());
        }
        // 5、插入问答数据
        int result = questionsDao.insert(questionsEntity);
        // 6、插入到关系表中
        questionsDao.insertQuestionTypeRelation(questionsEntity.getQuestionId(), typeId);
        // 删除问答缓存
        redisUtils.delQuestionListCache();
        return result;
    }


}